using System;
using System.Threading;
using CommonTypes.Server;
using Server.Model;
using Server.Services.Primary;

namespace Server.Services.RemoteObjects
{
    public class ClientToServer : MarshalByRefObject, IClientToServer
    {
        private readonly ServerData _servData;

        public ClientToServer( ServerData servData )
        {
            _servData = servData;
        }

        public bool active( )
        {
            return true;
        }

        public void GenerateTicket( String clientId, DateTime clientNonce )
        {
            if( _servData.Standalone )
                normalGenerateTicket( clientId, clientNonce );
            else
            {
                if( _servData.State == ServerState.ESTABLISHED )
                    normalGenerateTicket( clientId, clientNonce );
                else
                {
                    holdRequests( );
                    normalGenerateTicket( clientId, clientNonce );
                }
            }
        }

        private void holdRequests( )
        {
            while( _servData.State != ServerState.ESTABLISHED )
            {
                Thread.Sleep( 200 );
            }
        }

        private void normalGenerateTicket( String clientId, DateTime clientNonce )
        {
            if( ( clientId == null ) || ( clientId.Length == 0 ) || !_servData.UsersList.ContainsKey( clientId ) )
                return;

            if( !_servData.ServersInformation.Primary )
            {
                _servData.ServersInformation.ServersProxy[ _servData.ServersInformation.PrimaryId ].GenerateTicket( clientId, clientNonce );
                return;
            }
            else
                ProcessingRequests.GenerateTicket( clientId, clientNonce, _servData );
        }

        public String ResolveClient( String clientId )
        {
            if( _servData.Standalone )
                return normalResolveClient( clientId );
            else
            {
                if( _servData.State == ServerState.ADDREMOVE )
                {
                    holdRequests( );
                    return normalResolveClient( clientId );
                }
                else
                    return normalResolveClient( clientId );
            }
        }

        private string normalResolveClient( String clientId )
        {
            if( clientId.Length == 0 || !_servData.UsersList.ContainsKey( clientId ) )
                return "";

            System.Console.WriteLine( "Resolve request: " + clientId );

            return _servData.UsersList[ clientId ].Location;
        }

        public bool RegisterClientLocation( String clientId, String clientLocation )
        {
            if( _servData.Standalone )
                return normalRegisterClientLocation( clientId, clientLocation );
            else
            {
                if( _servData.State == ServerState.ESTABLISHED )
                    return normalRegisterClientLocation( clientId, clientLocation );
                else
                {
                    holdRequests( );
                    return normalRegisterClientLocation( clientId, clientLocation );
                }
            }
        }

        private bool normalRegisterClientLocation( String clientId, String clientLocation )
        {
            if( clientId.Length == 0 || clientLocation.Length == 0 )
                return false;

            if( !_servData.ServersInformation.Primary )
            {
                return _servData.ServersInformation.ServersProxy[ _servData.ServersInformation.PrimaryId ].RegisterClient( clientId, clientLocation, _servData.ServerLogicalClock );
            }
            else
                return ProcessingRequests.RegisterClient( clientId, clientLocation, _servData );
        }

        public bool UnregisterClientLocation( String clientId )
        {
            if( _servData.Standalone )
                return normalUnregisterClientLocation( clientId );
            else
            {
                if( _servData.State == ServerState.ESTABLISHED )
                    return normalUnregisterClientLocation( clientId );
                else
                {
                    holdRequests( );
                    return normalUnregisterClientLocation( clientId );
                }
            }
        }

        private bool normalUnregisterClientLocation( String clientId )
        {
            if( clientId.Length == 0 )
                return false;

            if( !_servData.ServersInformation.Primary )
            {
                return _servData.ServersInformation.ServersProxy[ _servData.ServersInformation.PrimaryId ].UnregisterClient( clientId, _servData.ServerLogicalClock );
            }
            else
                return ProcessingRequests.UnregisterClient( clientId, _servData );
        }

        public override object InitializeLifetimeService( )
        {
            return null;
        }
    }
}